package com.rocksea.checkservice;

import java.util.Arrays;

public class UDPPackage {



	public static final int ON_LINE = 0x008;
	public static final int OFF_LINE = 0x009;

	private static final byte Unknown = 0x00;
	private byte  cFrameHead = (byte)0xAB;      			// 帧头 0xAB
	public byte  cCommand = (byte) Unknown;;        	// 命令字
	private byte  machineID[] = new byte[16];   			// 机器编号
	private short nDataSize = 0;       					// 数据长度,0-512
	private byte[]  DataArray = null;       				// 数据，数据长度为0 时，本数据段为空
	private byte  cCheckSum = 0;      				 	// 校验和
	private byte  cFrameTail = (byte)0xAB;      			// 帧尾 0xAB

	private static final int MIN_PACKAGE_LENGTH = 22; // 最小包长度
	private int   times = 0;//记录发送次数
	private boolean  sendok = false;
	public UDPPackage()
	{
		cFrameHead = (byte) 0xAB;
		cFrameTail = (byte) 0xAB;
		cCommand = Unknown;
		nDataSize = 0;
		DataArray = null;
		cCheckSum = 0;
		times = 0;
		sendok = false;
		Arrays.fill(machineID, (byte)0);
	}
	private static final byte JZ_LOGIN = 0x20;
	public static final byte JZ_RESPOND = 0x30;
	public UDPPackage login(final byte machineid[],byte version[])//请求登录到服务器
	{
	    cFrameHead = (byte)0xAB;
	    cFrameTail = (byte)0xAB;
	    cCommand = JZ_LOGIN;
	    System.arraycopy(machineid, 0, machineID, 0, 16);
	    nDataSize = 0x10;
		DataArray = new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
		System.arraycopy(version,0,DataArray,0,16);
	    cCheckSum = 0;
	    cCheckSum = checkSum();		
		return this;
	}

	//串口收到数据,从UCHAR *buf创建UDPPackage
	public UDPPackage initWithBytes(final byte bytes[],final int len,int start)
	{
	    cFrameHead = bytes[start++];
	    cCommand = bytes[start++];
	    System.arraycopy(bytes, start, machineID, 0, 16);
	    start += 16;
	    nDataSize = (short) (  (0x000FF & bytes[start]) | ((0x00FF & bytes[start+1])<<8) );
	    start += 2;
		if( nDataSize>0 )
	    {
	        DataArray = new byte[nDataSize];
	        System.arraycopy(bytes, start, DataArray, 0, nDataSize);
	        start += nDataSize;
	    }
	    else
	        DataArray = null;
	    cCheckSum = bytes[start++];
	    cFrameTail = bytes[start++];
	    return this;
	}
	public static UDPPackage checkSumPackage(byte[] bytes,int start)
	{
		start = nextStartPos(bytes,start);//查找命令起始符号0xAB
	    if (start==-1)
	    	return null;

	    if ( (bytes.length-start) < MIN_PACKAGE_LENGTH )//最小GPS包22字节,登录回复包38字节
	    	return null;
	   
	   // 数据未接收齐
	   short udplen = (short) ( (0x000000FF & bytes[start+18]) | ((0x000000FF & bytes[start+19])<<8));
	   udplen += (short)22;
	   if (udplen>534  || udplen<(short)0)
	   {
		   start ++;
		   return checkSumPackage(bytes,start);
	   } 
	   if ( (int)udplen>(bytes.length-start) )
		   return null;
	   
	   // 帧尾字符不对
	   if (bytes[start + udplen -1] != (byte)0xAB)
	   {
		   start ++;
		   return checkSumPackage(bytes,start);
	   }
	   
	   // 校验和不对
	   if (checkSumBuffer(bytes,udplen,start)!=0)
	   {
		   start ++;
		   return checkSumPackage(bytes,start);
	   }
	   
	   // 有完整数据包了，提取该数据包并返回
	   return new UDPPackage().initWithBytes(bytes, udplen, start);
	}
	
	private static byte checkSumBuffer(byte bytes[],int len,int start)
	{
		//校验和(低位在前，高位在后)
		//buffer是指向需要校验数据缓冲区的指针，size是需要检验数据的总长度(字节为单位)	
	    byte cksum=0;
	    for (int i=start; i<start+len; i++)
	    {
	        cksum += bytes[i];
	    }
	    return cksum;
				
	}
	
	private static int nextStartPos(byte[] bytes,int start)
	{
        int pos = -1;
        for (int i=start; i<bytes.length; i++)
        {
                if (bytes[i]==(byte)0xAB)
                {
                        pos = i;
                        break;
                }
        }

        return pos;
	}
    
	//计算该包的校验和,(低位在前，高位在后)
	private byte checkSum()
	{
	    byte cksum = 0;
	    cksum += cFrameHead;
	    cksum += cCommand;
	    for (int i=0; i<16; i++) {
	        cksum += machineID[i];
	    }
	    cksum += nDataSize&0xFF;
	    cksum += nDataSize>>8&0xFF;
	    if (nDataSize>0 && DataArray!=null)
	    {
		    for (int i=0; i<nDataSize; i++)
		        cksum += DataArray[i];
	    }

	    cksum += cCheckSum;
	    cksum += cFrameTail;
	    
	    cksum = (byte)((short)0x0100-cksum);
	    return cksum;
	}
	
	public int length()
	{
	        return nDataSize+22;
	}
	
	public byte[] bytes()
	{
		byte[] bytes = new byte[nDataSize+22];

	    bytes[0] = cFrameHead;
	    bytes[1] = cCommand;
	    System.arraycopy(machineID, 0, bytes, 2, 16);

	    bytes[18] = (byte)(nDataSize&0xFF);
	    bytes[19] = (byte)(nDataSize>>8&0xFF);
        if( nDataSize>0 )
        {
        	System.arraycopy(DataArray, 0, bytes, 20, nDataSize);
        }
        bytes[20+nDataSize] = cCheckSum;
        bytes[21+nDataSize] = cFrameTail;
        return bytes;
	}
}
